package com.snjx.micro.oauth.gateway.config;

import cn.hutool.core.util.ArrayUtil;
import com.snjx.micro.oauth.gateway.authorization.AuthorizationManager;
import com.snjx.micro.oauth.gateway.component.RestAuthenticationEntryPoint;
import com.snjx.micro.oauth.gateway.component.RestfulAccessDeniedHandler;
import com.snjx.micro.oauth.gateway.constant.AuthConstant;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.jwt.Jwt;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
import org.springframework.security.oauth2.server.resource.authentication.ReactiveJwtAuthenticationConverterAdapter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.csrf.CookieServerCsrfTokenRepository;
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;


/**
 * @author suonanjiexi
 * @version 1.0
 * @Description TODO
 * @Date 2020/7/30 11:57 上午
 */
@AllArgsConstructor
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity(order = Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class ResourceServerConfig {
    private final AuthorizationManager authorizationManager;
    private final IgnoreUrlsConfig ignoreUrlsConfig;
    private final RestfulAccessDeniedHandler restfulAccessDeniedHandler;
    private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;
    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
        String[] arrayStrings=ArrayUtil.toArray(ignoreUrlsConfig.getUrls(),String.class);
        log.info("ignoreUrls  : {}",String.join(",",arrayStrings) );
        http.oauth2ResourceServer(
                jwt->jwt.jwt().jwtAuthenticationConverter(jwtAuthenticationConverter())
               );
        http.authorizeExchange(exchanges -> exchanges
                .pathMatchers(
                        //白名单配置
                        ArrayUtil.toArray(ignoreUrlsConfig.getUrls(),String.class)
                 ).permitAll()
                .anyExchange()
                //.pathMatchers("/api/hello").hasAuthority("SCOPE_messages")
                //鉴权管理器配置
                .access(authorizationManager)
                .and()
                .exceptionHandling()
                //处理未授权
                .accessDeniedHandler(restfulAccessDeniedHandler)
                //处理未认证
                .authenticationEntryPoint(restAuthenticationEntryPoint)
              )
                //.oauth2Client()
                //.and()
                //.oauth2Login()
                //.and()
                //.oauth2ResourceServer()
                //.and()
                //.csrf(csrf -> csrf.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
                //禁用csrf
                .csrf(csrf -> csrf.disable())
                .httpBasic(httpBasicSpec -> httpBasicSpec.disable())
                //
                //.httpBasic(Customizer.withDefaults())
                //登录
                //.formLogin(Customizer.withDefaults())
                //注销
                //.logout(Customizer.withDefaults())
                //自定义默认header
                /*.headers(headers -> headers
                        .frameOptions(frameOptions -> frameOptions.mode(XFrameOptionsServerHttpHeadersWriter.Mode.SAMEORIGIN)
                    )
                )*/
                //禁用header
               //.headers(headers -> headers.disable())

        ;
        return http.build();
    }

    @Bean
    public Converter<Jwt, ? extends Mono<? extends AbstractAuthenticationToken>> jwtAuthenticationConverter() {
        JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
        jwtGrantedAuthoritiesConverter.setAuthorityPrefix(AuthConstant.AUTHORITY_PREFIX);
        jwtGrantedAuthoritiesConverter.setAuthoritiesClaimName(AuthConstant.AUTHORITY_CLAIM_NAME);
        JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
        jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(jwtGrantedAuthoritiesConverter);
        return new ReactiveJwtAuthenticationConverterAdapter(jwtAuthenticationConverter);
    }
}
